package com.focusai.efairy.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.text.TextUtils;

import com.facebook.stetho.common.LogUtil;
import com.focusai.efairy.EFApplication;
import com.focusai.efairy.config.AppDirFileUtil;
import com.focusai.efairy.utils.log.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by luo_guangwen on 2017/10/18.
 */

public class ImageUtils {
    private final static String TAG = ImageUtils.class.getName();
    public final static int MAX_QUALITY_IN_WIFI = 90;
    public final static int MAX_QUALITY_IN_2G = 80;
    public final static int MAX_SIZE_IN_2G = 720;//720P
    public final static int MAX_SIZE_IN_3G = 1080;//1080P
    public final static int MAX_SIZE_IN_WIFI = MAX_SIZE_IN_3G;

    /**
     * @param sourcePath
     * @return
     */
    public static String saveCompressImageFile(String sourcePath) {
        return saveCompressImageFile(sourcePath, "");
    }

    public static String saveCompressImageFile(String sourcePath, String ext) {
        return saveImageFile(NetworkUtils.isWifiNetConnect(EFApplication.getContext()), sourcePath, false, ext);
    }

    private static String saveImageFile(boolean wifi, String sourcePath, boolean isWebViewUpload, String ext) {
        if (StringUtils.isStickBlank(sourcePath)) {
            return null;
        }
        Log.D(TAG, "saveImageFile begin");
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(sourcePath, opts);
        if (0 == opts.outHeight || 0 == opts.outWidth) {
            return null;
        }
        int[] ths = calculateWidthAndHeightByWifi(opts, wifi);
        int reqWidth = ths[0];
        int reqHeight = ths[1];

        File sourceFile = new File(sourcePath);
        String fileName;
        fileName = FileUtils.getMD5Hash(sourcePath + "_" + opts.outWidth + "X" + opts.outHeight + "_" + sourceFile.lastModified()) + "_" + reqWidth + "X" + reqHeight;

        String cacheFilePath = AppDirFileUtil.getImageDirPath() + File.separator + fileName;
        if (!TextUtils.isEmpty(ext)) {
            cacheFilePath = cacheFilePath + "." + ext;
        }
        File cacheFile = new File(cacheFilePath);
        if (cacheFile.exists() && cacheFile.length() > 0) {
            Log.D(TAG, "saveImageFile file is exist");
            //已经处理过的图片，直接返回处理结果路径
            return cacheFilePath;
        }

        int sampleSize = calculateInSampleSizeByWiFi(wifi, opts);
        opts.inSampleSize = sampleSize;
        opts.inJustDecodeBounds = false;
        Bitmap bm = getBitmapByOptions(sourcePath, opts);
        Log.D(TAG, "saveImageFile image to bitmap2 " + sampleSize);
        if (bm != null) {
            int h = bm.getHeight();
            int w = bm.getWidth();
            if (w * h > reqWidth * reqHeight) {
                //如果采样后的图片仍然大于目标尺寸就要做缩放处理
                try {
                    Bitmap tempBitmap = Bitmap.createScaledBitmap(bm, reqWidth, reqHeight, true);
                    Log.D(TAG, "saveImageFile image scaled");
                    bm.recycle();
                    bm = tempBitmap;
                } catch (OutOfMemoryError e) {
                    e.printStackTrace();
                }
            }
            cacheFilePath = saveRotatedBitmap(bm, sourcePath, cacheFilePath);
            bm.recycle();
        } else {
            cacheFilePath = null;
        }
        return cacheFilePath;
    }

    private static int[] calculateWidthAndHeightByWifi(BitmapFactory.Options opts, boolean wifi) {
        int reqWidth, reqHeight;
        if (opts.outWidth > opts.outHeight)//横图
        {
            reqHeight = wifi ? MAX_SIZE_IN_WIFI : MAX_SIZE_IN_2G;
            reqWidth = opts.outWidth * reqHeight / opts.outHeight;
        }//竖图
        else {
            reqWidth = wifi ? MAX_SIZE_IN_WIFI : MAX_SIZE_IN_2G;
            reqHeight = opts.outHeight * reqWidth / opts.outWidth;
        }
        return new int[]{reqWidth, reqHeight};
    }

    private static int calculateInSampleSizeByWiFi(boolean wifi, BitmapFactory.Options opts) {
        int[] gTh = calculateWidthAndHeightByWifi(opts, wifi);
        int reqWidth = gTh[0];
        int reqHeight = gTh[1];
        return calculateInSampleSize(opts, reqWidth, reqHeight);
    }

    private static int calculateInSampleSize(BitmapFactory.Options opts, int reqWidth, int reqHeight) {
        int maxNumOfPixels = reqWidth * reqHeight;
        int orgNumOfPixels = opts.outHeight * opts.outWidth;
        if (maxNumOfPixels * 10 > orgNumOfPixels * 11) {
            return 1;
        } else {
            return calculateInSampleSize2(opts, reqWidth, reqHeight);
        }
    }

    //计算图片的缩放值
    public static int calculateInSampleSize2(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {
            final int heightRatio = Math.round((float) height / (float) reqHeight);
            final int widthRatio = Math.round((float) width / (float) reqWidth);
            inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;
            if (inSampleSize <= 0) {
                inSampleSize = 1;
            }
        }
        return inSampleSize;
    }

    /**
     * 获取bitmap，节省内存，替代decodeFile或decodeStream方法
     *
     * @param sourcePath 图片路径
     * @param options
     * @return
     */
    public static Bitmap getBitmapByOptions(String sourcePath, BitmapFactory.Options options) {
        FileInputStream fs = null;
        Bitmap bm = null;
        try {
            fs = new FileInputStream(sourcePath);
        } catch (FileNotFoundException fnfException) {
            fnfException.printStackTrace();
        }
        if (fs != null) {
            try {
                bm = BitmapFactory.decodeFileDescriptor(fs.getFD(), null, options);
            } catch (IOException ioException) {
                ioException.printStackTrace();
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
            } finally {
                try {
                    fs.close();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
        LogUtil.d(TAG, bm != null ? "bm not null" : "bm null");
        return bm;
    }

    /**
     * 保存旋转正后的图片路径
     *
     * @param bm
     * @param sourceFile
     * @param dstPath
     * @return
     */
    public static String saveRotatedBitmap(Bitmap bm, String sourceFile, String dstPath) {
        int angle = readPictureDegree(sourceFile);
        if (angle % 360 != 0) {
            bm = rotate(angle, bm);
            LogUtil.d(TAG, "saveRotatedBitmap rotate image");
            angle = 0;
        } else if (TextUtils.isEmpty(dstPath)) {
            return sourceFile;
        }
        return saveImageBitmap(bm, angle, sourceFile, dstPath);
    }

    /**
     * @param bitmap
     * @param angle
     * @param path
     * @param newPath 空时则覆盖原path的路径
     * @return
     */
    public static String saveImageBitmap(Bitmap bitmap, int angle, String path, String newPath) {
        FileOutputStream outputStream = null;
        File file;
        try {
            if (TextUtils.isEmpty(newPath)) {
                file = new File(path);
            } else {
                file = new File(newPath);
            }
            outputStream = new FileOutputStream(file);
            if (bitmap != null) {
                if (bitmap.compress(Bitmap.CompressFormat.JPEG, MAX_QUALITY_IN_WIFI, outputStream)) {
                    if (TextUtils.isEmpty(newPath)) {
                        savePictureDegree(path, angle);
                    } else {
                        savePictureDegree(newPath, angle);
                    }
                }
            }
        } catch (IOException e) {
            file = null;
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return file != null ? file.getAbsolutePath() : null;
    }

    /**
     * 设置图片文件Exif角度信息
     *
     * @param filepath    文件路径
     * @param orientation 角度 为正数 90 * i, i >= 0
     */
    public static void savePictureDegree(String filepath, int orientation) {
        ExifInterface exif = null;
        try {
            exif = new ExifInterface(filepath);
            switch (orientation) {
                case 0: {
                    exif.setAttribute(ExifInterface.TAG_ORIENTATION,
                            String.valueOf(ExifInterface.ORIENTATION_NORMAL));
                }
                break;
                case 90: {
                    exif.setAttribute(ExifInterface.TAG_ORIENTATION,
                            String.valueOf(ExifInterface.ORIENTATION_ROTATE_90));
                }
                break;
                case 180: {
                    exif.setAttribute(ExifInterface.TAG_ORIENTATION, String
                            .valueOf(ExifInterface.ORIENTATION_ROTATE_180));
                }
                break;
                case 270: {
                    exif.setAttribute(ExifInterface.TAG_ORIENTATION, String
                            .valueOf(ExifInterface.ORIENTATION_ROTATE_270));
                }
                break;
                default: {
                    exif.setAttribute(ExifInterface.TAG_ORIENTATION,
                            String.valueOf(ExifInterface.ORIENTATION_NORMAL));
                }
            }
            exif.saveAttributes();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 读取图片属性：旋转的角度
     *
     * @param path 图片绝对路径
     * @return degree旋转的角度
     */
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }
    /**
     * 图片旋转
     * 原图b会被释放
     *
     * @param b
     * @param degrees
     * @return
     */
    public static Bitmap rotate(int degrees, Bitmap b) {
        if (degrees != 0 && b != null) {
            Matrix m = new Matrix();

            if (degrees == 180)// 某些系统中旋转180无效,通过两次旋转90度达到180效果
            {
                for (int i = 0; i < 2; i++) {
                    m.setRotate(90, (float) b.getWidth() / 2,
                            (float) b.getHeight() / 2);
                    try {
                        Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
                                b.getHeight(), m, true);
                        if (b != b2) {
                            b.recycle();
                            b = b2;
                        }
                    } catch (OutOfMemoryError ex) {
                        return b;
                    }
                }
            } else {
                m.setRotate(degrees, (float) b.getWidth() / 2,
                        (float) b.getHeight() / 2);
                try {
                    Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
                            b.getHeight(), m, true);
                    if (b != b2) {
                        b.recycle();
                        b = b2;
                    }
                } catch (OutOfMemoryError ex) {
                    return b;
                }
            }
        }
        return b;
    }
}
